/**
 * PAcote.
 */
package br.org.bertol.mestrado.engine;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CountDownLatch;

import org.apache.poi.ss.usermodel.Workbook;

import br.org.bertol.mestrado.Verify;
import br.org.bertol.mestrado.engine.fitness.Objective;
import br.org.bertol.mestrado.engine.optimisation.entity.AbstractUnit;
import br.org.bertol.mestrado.engine.optimisation.entity.StoreResult;
import br.org.bertol.mestrado.util.RandomSolution;
import br.org.bertol.mestrado.util.Report;

/**
 * @author contaqualquer
 * @param <T>
 *            Tipo de objeto do problema
 */
public abstract class AbstractSearchEngine<T> extends Thread {
    // 1 starter para todos as her�sticas
    /***/
    protected transient CountDownLatch    startHeuristic = new CountDownLatch(
                                                                 1);

    // 5 contadores de término de heuristica
    // para cada resultado conseguido no greedy
    /***/
    protected transient CountDownLatch    doneHeuristic;

    /***/
    protected transient CountDownLatch    startSystem;

    /***/
    protected transient CountDownLatch    stopSystem;

    /***/
    protected transient String            systemID;

    /***/
    protected transient String            storePath;

    /***/
    protected transient int               numIteracoes;

    /***/
    protected transient Verify<T>         verify;

    /***/
    final transient EnumSet<Objective>    typeEvaluation;

    /***/
    protected transient RandomSolution<T> randomSolution;

    /** Marca início da execução do processso. */
    protected long                        initTime;

    /** Marca fim da execução do processso. */
    protected long                        stopTime;

    private final transient Report<T>     report;

    /**
     * @param startS
     *            Barreira de início
     * @param stopS
     *            Barreira de fim
     * @param numEval
     *            Número de avaliação
     * @param storeP
     *            Caminho onde salvar resultados
     * @param sID
     *            Identificação do sistema
     * @param objectives
     *            Objetivos do problema
     */
    public AbstractSearchEngine(final CountDownLatch startS,
        final CountDownLatch stopS, final int numEval, final String storeP,
        final String sID,
        final Objective... objectives) {
        super();

        // inicia inst�ncia do verificador
        verify = new Verify<T>(objectives, storeP, sID);

        typeEvaluation = EnumSet.noneOf(Objective.class);

        typeEvaluation.addAll(Arrays.asList(verify.getObjectives()));

        setName("Sistema " + sID + " | Tipo avaliação " + typeEvaluation
                + " | Nº de iterações " + numEval);

        startSystem = startS;

        stopSystem = stopS;

        systemID = sID;

        storePath = storeP;

        numIteracoes = numEval;

        randomSolution = new RandomSolution<T>();

        randomSolution.setVerify(verify);

        initTime = 0;

        stopTime = 0;

        report = new Report<T>();

    }

    /**
     * Armazena e consolida os resultados.
     * @param units
     *            Lista de resultados brutos
     * @param hash
     *            TODO
     */
    protected final void consolidateResult(
            final List<? extends AbstractUnit<T>>
            units, final HashMap<String, ? extends Number> hash) {

        final List<List<StoreResult<T>>> consolidateResult =
                new ArrayList<List<StoreResult<T>>>();

        final List<StoreResult<T>> results = new ArrayList<StoreResult<T>>();

        for (final AbstractUnit<T> unit : units) {

            results.add(unit.getConsolidateResult());

        }

        consolidateResult.add(results);

        report.setConsolidateResult(consolidateResult);

        report.setInitTime(initTime);

        report.setStopTime(stopTime);

        report.setSystemID(systemID);

        report.setObjectives(verify.getObjectives());

        report.setSet(hash);

    }

    /**
     * @param fileName
     *            Nome do arquivo
     * @return {@link Workbook} Planilha excel
     * @throws IOException
     *             Caso erro ao abrir arquivo
     */
    protected final Workbook getInputStream(final String fileName)
            throws IOException {

        return report.getInputStream(fileName);

    }

    /**
     * @param workbook
     */
    public final void storeResultXls(final Workbook workbook) {
        report.getResultSheet(workbook);
    }

    /**
     * @param out
     *            Arquivo de saída
     * @throws IOException
     *             Err ao abrir o arquivo
     */
    protected final void storeResultTxt(final String out) throws IOException {

        final PrintWriter outFile = new PrintWriter(new BufferedWriter(
                new FileWriter(out, true)));

        report.storeResultAnalisis(outFile);

        outFile.close();
    }
}
